VT-d: Sanity check ACPI DMAR struct lengths.
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 25 Mar 2010 09:32:21 +0000 (09:32 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 25 Mar 2010 09:32:21 +0000 (09:32 +0000)
Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/drivers/passthrough/vtd/dmar.c

index 857ba861d5f62c4be76d10867777d41b70632a81..310a66da3ed2267dfa9bd0aea81b81729e2e7276 100644 (file)
@@ -361,6 +361,17 @@ static int __init acpi_parse_dev_scope(void *start, void *end,
     return 0;
 }
 
+static int __init acpi_dmar_check_length(
+    struct acpi_dmar_entry_header *h, unsigned int min_len)
+{
+    if ( h->length >= min_len )
+        return 0;
+    dprintk(XENLOG_ERR VTDPREFIX,
+            "Invalid ACPI DMAR entry length: 0x%x\n",
+            h->length);
+    return -EINVAL;
+}
+
 static int __init
 acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
 {
@@ -368,9 +379,12 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
     void *dev_scope_start, *dev_scope_end;
     struct acpi_drhd_unit *dmaru;
     void *addr;
-    int ret = 0;
+    int ret;
     static int include_all = 0;
 
+    if ( (ret = acpi_dmar_check_length(header, sizeof(*drhd))) != 0 )
+        return ret;
+
     dmaru = xmalloc(struct acpi_drhd_unit);
     if ( !dmaru )
         return -ENOMEM;
@@ -470,7 +484,10 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
     struct acpi_rmrr_unit *rmrru;
     void *dev_scope_start, *dev_scope_end;
     u64 base_addr = rmrr->base_address, end_addr = rmrr->end_address;
-    int ret = 0;
+    int ret;
+
+    if ( (ret = acpi_dmar_check_length(header, sizeof(*rmrr))) != 0 )
+        return ret;
 
 #ifdef CONFIG_X86
     /* This check is here simply to detect when RMRR values are
@@ -564,10 +581,13 @@ acpi_parse_one_atsr(struct acpi_dmar_entry_header *header)
 {
     struct acpi_table_atsr *atsr = (struct acpi_table_atsr *)header;
     struct acpi_atsr_unit *atsru;
-    int ret = 0;
+    int ret;
     static int all_ports;
     void *dev_scope_start, *dev_scope_end;
 
+    if ( (ret = acpi_dmar_check_length(header, sizeof(*atsr))) != 0 )
+        return ret;
+
     atsru = xmalloc(struct acpi_atsr_unit);
     if ( !atsru )
         return -ENOMEM;
@@ -610,7 +630,10 @@ acpi_parse_one_rhsa(struct acpi_dmar_entry_header *header)
 {
     struct acpi_table_rhsa *rhsa = (struct acpi_table_rhsa *)header;
     struct acpi_rhsa_unit *rhsau;
-    int ret = 0;
+    int ret;
+
+    if ( (ret = acpi_dmar_check_length(header, sizeof(*rhsa))) != 0 )
+        return ret;
 
     rhsau = xmalloc(struct acpi_rhsa_unit);
     if ( !rhsau )
@@ -659,6 +682,11 @@ static int __init acpi_parse_dmar(struct acpi_table_header *table)
     while ( ((unsigned long)entry_header) <
             (((unsigned long)dmar) + table->length) )
     {
+        ret = acpi_dmar_check_length(
+            entry_header, sizeof(struct acpi_dmar_entry_header));
+        if ( ret )
+            break;
+
         switch ( entry_header->type )
         {
         case ACPI_DMAR_DRHD: